package com.wenchao.demoworkmanager;

import android.os.Bundle;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.work.Constraints;
import androidx.work.Data;
import androidx.work.ExistingPeriodicWorkPolicy;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkContinuation;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;
import androidx.work.WorkRequest;

import com.google.common.util.concurrent.ListenableFuture;
import com.wenchao.demoworkmanager.databinding.ActivityMainBinding;
import com.wenchao.demoworkmanager.works.UploadLogWork;
import com.wenchao.demoworkmanager.works.UploadLogsWork;

import java.util.Arrays;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @author zhangwenchao
 * <p>
 * 冲突解决政策 ExistingWorkPolicy
 * REPLACE : 用新工作替换现有工作。此选项将取消现有工作。
 * KEEP : 保留现有工作，并忽略新工作。
 * APPEND : 将新工作附加到现有工作的末尾。此选项会将新工作链接到现有工作，并在现有工作完成后运行。并且现有工作将成为新工作的先决条件。如果现有工作为 CANCELLED 或者 FAILED 状态，新工作也会变为 CANCELLED 或者 FAILED 状态。
 * APPEND_OR_REPLACE : 此选项类似于 APPEND，不过它不依赖于现有工作的状态。即使现有工作为 CANCELLED 或者 FAILED 状态，新工作仍旧会运行。
 * <p>
 * Worker 提交系统
 * enqueue() 方法将 WorkRequest 提交到系统。
 * WorkManager.enqueueUniqueWork（用于一次性工作）
 * WorkManager.enqueueUniquePeriodicWork（用于定期工作）
 * 这两种方法都有3个参数：
 * 1. uniqueWorkName - 用于标识唯一工作请求的 String。
 * 2. existingWorkPolicy - 用于如果已有使用该名称且尚未完成的唯一工作(链)，应该执行什么操作。参照冲突解决政策。
 * 3. workRequest - 需要调度的 WorkRequest。
 * <p>
 * 约束任务
 * BatteryNotLow 如果设置为 true，那么当设备处于“电量不足模式”时，工作不会运行。
 * RequiresCharging 如果设置为 true，那么工作只能在设备充电时运行。
 * DeviceIdle 如果设置为 true，则要求用户的设备必须处于空闲状态，才能运行工作。如果您要运行批量操作，否则可能会降低用户设备上正在积极运行的其他应用的性能，建议您使用此约束。
 * StorageNotLow 如果设置为 true，那么当用户设备上的存储空间不足时，工作不会运行。
 */
public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private UUID id;
    private static final String TAG = "super";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        addListener();
    }

    private void addListener() {
        // 开启一次的任务
        binding.btnOnetime.setOnClickListener(view -> {
            WorkManager.getInstance(this).cancelAllWork();

            WorkRequest workRequest = OneTimeWorkRequest.from(UploadLogWork.class);
            WorkManager.getInstance(this)
                    .enqueue(workRequest);
        });

        // 启动日志重复上传任务,最小间隔为15分钟
        binding.btnPeriodic.setOnClickListener(view -> {
            WorkManager.getInstance(this).cancelAllWork();

            PeriodicWorkRequest workRequest = new PeriodicWorkRequest
                    .Builder(UploadLogWork.class, 15, TimeUnit.MINUTES)
                    .build();
            WorkManager
                    .getInstance(this)
                    .enqueueUniquePeriodicWork(
                            "sendLogs", ExistingPeriodicWorkPolicy.KEEP, workRequest);
            id = workRequest.getId();
        });

        // 充电的情况下上传日志
        binding.btnCharge.setOnClickListener(view -> {
            WorkManager.getInstance(this).cancelAllWork();

            Constraints constraints = new Constraints.Builder()
                    .setRequiresCharging(true)
                    .build();
            WorkRequest workRequest = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setConstraints(constraints)
                    .build();
            WorkManager.getInstance(this)
                    .enqueue(workRequest);
        });

        // 延迟上传日志
        binding.btnDelay.setOnClickListener(view -> {
            WorkManager.getInstance(this).cancelAllWork();

            WorkRequest workRequest = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInitialDelay(10, TimeUnit.SECONDS)
                    .build();
            WorkManager.getInstance(this)
                    .enqueue(workRequest);
        });

        // 给任务传数据,通过 Data 这种方式的输入输出只适用于 OneTimeWorkRequest.
        binding.btnParams.setOnClickListener(view -> {
            WorkManager.getInstance(this).cancelAllWork();

            Data data = new Data.Builder().putString("work_content", "hello world").build();
            WorkRequest workRequest = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(data)
                    .build();
            WorkManager.getInstance(this)
                    .enqueue(workRequest);

            WorkManager.getInstance(this).getWorkInfoByIdLiveData(workRequest.getId())
                    .observe(this, workInfo -> {
                        if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) {
                            String result = workInfo.getOutputData().getString("work_result");
                            Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
                        }
                    });
        });

        // 查看重复任务的状态
        binding.btnView.setOnClickListener(view -> {
            ListenableFuture<WorkInfo> workInfoById = WorkManager.getInstance(this).getWorkInfoById(id);
            try {
                WorkInfo workInfo = workInfoById.get();
                WorkInfo.State state = workInfo.getState();
                Toast.makeText(this, "任务状态：" + state, Toast.LENGTH_SHORT).show();
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 任务链
        binding.btnWorkList.setOnClickListener(view -> {
            WorkManager.getInstance(this).cancelAllWork();

            OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work1").build())
                    .build();
            OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work2").build())
                    .build();
            OneTimeWorkRequest work3 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work3").build())
                    .build();
            OneTimeWorkRequest work4 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work4").build())
                    .build();
            OneTimeWorkRequest work5 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work5").build())
                    .build();
            OneTimeWorkRequest work6 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work6").build())
                    .build();
            WorkManager.getInstance(this)
                    .beginWith(Arrays.asList(work1, work2))
                    .then(work3)
                    .then(Arrays.asList(work4, work5))
                    .then(work6)
                    .enqueue();
        });

        // 任务链-支持子任务链
        // 需要提醒的是：WorkContinuation 定义的子链不能保证执行的先后顺序，只能保证子链中的 worker 是按顺序执行的。
        binding.btnWorkChains.setOnClickListener(view -> {
            WorkManager.getInstance(this).cancelAllWork();

            OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work1").build())
                    .build();
            OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work2").build())
                    .build();
            OneTimeWorkRequest work3 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work3").build())
                    .build();
            OneTimeWorkRequest work4 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work4").build())
                    .build();
            OneTimeWorkRequest work5 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work5").build())
                    .build();
            OneTimeWorkRequest work6 = new OneTimeWorkRequest.Builder(UploadLogWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "work6").build())
                    .build();

            WorkContinuation chain1 = WorkManager.getInstance(this)
                    .beginWith(work1)
                    .then(work2);

            WorkContinuation chain2 = WorkManager.getInstance(this)
                    .beginWith(work3)
                    .then(work4);

            WorkContinuation chain3 = WorkContinuation
                    .combine(Arrays.asList(chain1, chain2))
                    .then(Arrays.asList(work5, work6));
            chain3.enqueue();
        });

        // 有进度的任务
        binding.btnProgressWork.setOnClickListener(view -> {
            binding.btnProgressWork.setEnabled(false);

            WorkManager.getInstance(this).cancelAllWork();

            OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(UploadLogsWork.class)
                    .setInputData(new Data.Builder().putString("work_content", "progress work").build())
                    .build();
            WorkManager.getInstance(this)
                    .enqueue(workRequest);

            WorkManager.getInstance(this)
                    .getWorkInfoByIdLiveData(workRequest.getId())
                    .observe(this, workInfo -> {
                        if (workInfo != null) {
                            if (workInfo.getState() == WorkInfo.State.SUCCEEDED) {
                                binding.btnProgressWork.setText("有进度的任务");
                                Toast.makeText(this, "日志批量上传完成！", Toast.LENGTH_SHORT).show();
                                binding.btnProgressWork.setEnabled(true);
                                return;
                            }

                            Data progress = workInfo.getProgress();
                            int value = progress.getInt(UploadLogsWork.PROGRESS, 0);
                            binding.btnProgressWork.setText(String.format(Locale.CHINA, "日志上传进度:%d%%", value));
                        }
                    });
        });

        // 取消所有的任务
        binding.btnCancelAll.setOnClickListener(view -> {
            WorkManager.getInstance(this).cancelAllWork();
        });
    }
}